package xcmg.device.service.sale;

import com.github.pagehelper.PageInfo;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import xcmg.device.dao.entity.PriMaterialsDO;
import xcmg.device.dao.entity.PubMaterialsDO;
import xcmg.device.dao.entity.account.ArapDO;
import xcmg.device.dao.entity.account.ArapDetailDO;
import xcmg.device.dao.entity.agentReturn.AgentReturnDO;
import xcmg.device.dao.entity.company.CompanyDealerDO;
import xcmg.device.dao.entity.company.CompanyInfoDO;
import xcmg.device.dao.entity.sale.SalesBillDO;
import xcmg.device.dao.entity.sale.SalesBillDetailDO;
import xcmg.device.dao.entity.sale.SalesOutBillDO;
import xcmg.device.dao.entity.sale.SalesOutBillDetailDO;
import xcmg.device.dao.entity.sale.SalesOutPostDO;
import xcmg.device.dao.entity.warehouse.WarehouseDO;
import xcmg.device.dao.mapper.CompanyDealerMapper;
import xcmg.device.dao.mapper.CompanyInfoMapper;
import xcmg.device.dao.mapper.MaterialLocationRelationMapper;
import xcmg.device.dao.mapper.PriMaterialsMapper;
import xcmg.device.dao.mapper.PubMaterialsMapper;
import xcmg.device.dao.mapper.account.ArapDetailMapper;
import xcmg.device.dao.mapper.account.ArapMapper;
import xcmg.device.dao.mapper.agentReturn.AgentReturnDOMapper;
import xcmg.device.dao.mapper.delivery.DeliveryNoteMapper;
import xcmg.device.dao.mapper.sale.SalesBillDetailMapper;
import xcmg.device.dao.mapper.sale.SalesBillMapper;
import xcmg.device.dao.mapper.sale.SalesOutBillDetailMapper;
import xcmg.device.dao.mapper.sale.SalesOutBillMapper;
import xcmg.device.dao.mapper.sale.SalesOutPostMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseAreaLocationDOMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseDOMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseDeliveryDetailMapper;
import xcmg.device.infra.BeanUtil;
import xcmg.device.infra.CalcUtil;
import xcmg.device.infra.ErrorCode;
import xcmg.device.infra.ExportUtil;
import xcmg.device.infra.enums.BillDesc;
import xcmg.device.infra.enums.SaleOutEnum;
import xcmg.device.service.GenDocumentService;
import xcmg.device.service.agent.ServiceStaffQuotaService;
import xcmg.device.service.barcode.BarcodeService;
import xcmg.device.service.company.CompanyInfoService;
import xcmg.device.service.threeParty.BaiduApiService;
import xcmg.device.service.vo.agent.ServiceStaffQuotaUseVO;
import xcmg.device.service.vo.barcode.BarcodeManageVO;
import xcmg.device.service.vo.barcode.SplitNumVO;
import xcmg.device.service.vo.basic.MaterialLocationRelationVO;
import xcmg.device.service.vo.basic.MaterialsSearchVO;
import xcmg.device.service.vo.basic.MaterialsVO;
import xcmg.device.service.vo.company.CompanyInfoVO;
import xcmg.device.service.vo.delivery.DeliveryNoteAddVO;
import xcmg.device.service.vo.delivery.DeliveryNoteDetailVO;
import xcmg.device.service.vo.delivery.DeliveryNoteVO;
import xcmg.device.service.vo.sale.SaleOutAddVO;
import xcmg.device.service.vo.sale.SaleOutAutoAddDetailVO;
import xcmg.device.service.vo.sale.SaleOutAutoAddVO;
import xcmg.device.service.vo.sale.SalesOutBillDetailVO;
import xcmg.device.service.vo.sale.SalesOutBillVO;
import xcmg.device.service.vo.threeParty.BaiduTranslateResultDO;
import xcmg.device.service.vo.warehouse.WarehouseDeliveryRecordAddVO;
import xcmg.device.service.vo.warehouse.app.EnableAndOccupyVO;
import xcmg.device.service.warehouse.CommonService;
import xcmg.device.service.warehouse.WarehouseDeliveryRecordService;
import xcmg.device.service.warehouse.WarehouseDeliveryService;
import xcmg.device.service.warehouse.WarehouseInventoryService;
import xcmg.device.util.CompanyUtil;
import xcmg.device.util.DecimalUtil;
import xcmg.device.util.JedisUtils;
import yb.ecp.fast.feign.FastGenClient;
import yb.ecp.fast.infra.infra.PageCommonVO;
import yb.ecp.fast.infra.infra.SearchCommonVO;
import yb.ecp.fast.infra.infra.log.LogHelper;
import yb.ecp.fast.infra.util.ListUtil;
import yb.ecp.fast.infra.util.PageHelperPlus;
import yb.ecp.fast.infra.util.StringUtil;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Created by wrg on 2019/4/24.
 */
@Service
public class SalesBillOutService {
    @Autowired
    private SalesOutBillMapper salesOutBillMapper;
    @Autowired
    private WarehouseDOMapper warehouseDOMapper;
    @Autowired
    private SalesOutBillDetailMapper salesOutBillDetailMapper;
    @Autowired
    private WarehouseDeliveryDetailMapper warehouseDeliveryDetailMapper;
    @Autowired
    private SalesBillDetailMapper salesBillDetailMapper;
    @Autowired
    private WarehouseInventoryService warehouseInventoryService;
    @Autowired
    private PriMaterialsMapper priMaterialsMapper;
    @Autowired
    private FastGenClient fastGenClient;
    @Autowired
    private GenDocumentService genDocumentService;
    @Autowired
    private WarehouseDeliveryService warehouseDeliveryService;
    @Autowired
    private SalesBillService salesBillService;
    @Autowired
    private SalesBillMapper salesBillMapper;
    @Autowired
    private ArapMapper arapMapper;
    @Autowired
    private HttpServletResponse response;
    @Autowired
    private ServiceStaffQuotaService serviceStaffQuotaService;
    @Autowired
    private CompanyInfoService companyInfoService;
    @Autowired
    private CompanyDealerMapper companyDealerMapper;
    @Autowired
    private ArapDetailMapper arapDetailMapper;
    @Autowired
    private MaterialLocationRelationMapper materialLocationRelationMapper;
    @Autowired
    private WarehouseAreaLocationDOMapper warehouseAreaLocationDOMapper;
    @Autowired
    private PubMaterialsMapper pubMaterialsMapper;
    @Autowired
    private BaiduApiService baiduApiService;


    @Autowired
    private SalesOutPostMapper salesOutPostMapper;

    @Autowired
    private AgentReturnDOMapper agentReturnDOMapper;

    @Autowired
    private WarehouseDeliveryRecordService warehouseDeliveryRecordService;

    @Autowired
    private BarcodeService barcodeService;

    @Autowired
    private CompanyInfoMapper companyInfoMapper;


    /**
     * 进出口海外客户发票号
     */
    public static final String JCK_INVOICE_NO_GEN_PRE = "JCK_INVOICE_NO_GEN_PRE";

    /**
     * 新增销售出库单
     *
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public synchronized ErrorCode add(SaleOutAddVO addVO, String userId, String orgId, String userName) throws Exception {
        String salesOutBillNo = genDocumentService.getDocumentNo(BillDesc.SalesOutNo);
        Integer status = addVO.getStatus();
        List<DeliveryNoteDetailVO> deliveryNoteDetailVOList = new ArrayList<>();
        SalesOutBillVO headerInfo = addVO.getHeaderInfo();
        List<SalesOutBillDetailVO> materialList = addVO.getMaterialList();
        boolean result = checkOrderQty(materialList);
        if (result) {
            return ErrorCode.DeliveryNoteQtyError;
        }

        BigDecimal totalCostPrice = BigDecimal.ZERO;
        BigDecimal totalPrice = BigDecimal.ZERO;
        for (SalesOutBillDetailVO detailVO : materialList) {
            String detailId = fastGenClient.newGuidText().getValue();
            if (StringUtils.isBlank(detailId)) {
                throw new Exception("新增销售出库单失败");
            }
            SalesOutBillDetailDO detailDO = getSalesOutBillDetailDO(userId, orgId, salesOutBillNo, headerInfo, detailVO, detailId, status);
            // 借用转销售，扣减销售人员额度
            boolean updateQuota = updateQuota(headerInfo, detailDO);
            if (updateQuota) {
                throw new Exception("扣减服务人员额度失败");
            }

            //借用单转销售 更新出库状态与出库数量
            updateOutboundStatusAndQty(headerInfo, detailDO);
            updateOrderStatus(detailVO, detailDO, orgId);

            int insCount = salesOutBillDetailMapper.insertSelective(detailDO);
            if (insCount <= 0) {
                throw new Exception("新增销售出库单失败");
            }
            BigDecimal costPrice = detailDO.getCostPrice() == null ? BigDecimal.ZERO : detailDO.getCostPrice();
            BigDecimal thisShipQty = detailDO.getThisShipQty() == null ? BigDecimal.ZERO : detailDO.getThisShipQty();
            totalCostPrice = totalCostPrice.add(costPrice.multiply(thisShipQty));
            totalPrice = totalPrice.add(detailDO.getSinglePrice().multiply(thisShipQty));

            DeliveryNoteDetailVO deliveryNoteDetailVO = new DeliveryNoteDetailVO();
            deliveryNoteDetailVO.setMaterialsNo(detailDO.getMaterialNo());
            deliveryNoteDetailVO.setMaterialsDes(detailDO.getMaterialDes());
            deliveryNoteDetailVO.setUnit(detailDO.getUnit());
            deliveryNoteDetailVO.setDeliveryQty(detailDO.getThisShipQty());
            deliveryNoteDetailVOList.add(deliveryNoteDetailVO);
            if (detailDO.getIsState() == 1) { // 提交状态更新销售单创建状态。与创建数量
                boolean updateResult = salesBillService.updateCreateOutStatus(detailDO.getSalesBillNo(), detailDO.getMaterialNo(),
                        detailDO.getThisShipQty(), null, BigDecimal.ZERO, null);
                if (!updateResult) {
                    throw new Exception("新增销售出库单失败");
                }
            }
        }

        headerInfo.setCostTotal(totalCostPrice);
        headerInfo.setTotalPrice(totalPrice);
        SalesOutBillDO salesOutBillDO = getSalesOutBillDO(userId, orgId, userName, salesOutBillNo, headerInfo);
        if (status == 0) {
            int insSalesOutCount = salesOutBillMapper.insertSelective(salesOutBillDO);
            if (insSalesOutCount <= 0) {
                throw new Exception("新增销售出库单失败");
            }
        } else {
            salesOutBillDO.setIsState((short) 1);
            if (StringUtils.isNotBlank(salesOutBillDO.getBorrowBillNo())) {
                salesOutBillDO.setOutboundStatus((short) 2);
                salesOutBillDO.setOutboundDate(new Date());
            }
            int insSalesOutCount = salesOutBillMapper.insertSelective(salesOutBillDO);
            if (insSalesOutCount <= 0) {
                throw new Exception("新增销售出库单失败");
            }

            if (salesOutBillDO.getOutboundStatus() != 2) {
                // 新增出库单时新增发货事物单
                DeliveryNoteAddVO deliveryNoteAddVO = new DeliveryNoteAddVO();
                DeliveryNoteVO deliveryNoteVO = new DeliveryNoteVO();
                deliveryNoteVO.setDeliveryNo(salesOutBillNo);
                deliveryNoteVO.setOutLocation(headerInfo.getOutArea());
                deliveryNoteAddVO.setHeaderInfo(deliveryNoteVO);
                deliveryNoteAddVO.setMaterialList(deliveryNoteDetailVOList);
                warehouseDeliveryService.saveByDeliveryNoteOut(deliveryNoteAddVO, userId, orgId);
            }
            if (needGenArap(orgId)) {
                this.balanceAdd(salesOutBillDO, orgId);
            }
        }
        return ErrorCode.Success;
    }

    /**
     * 2019-12-02 代理商和施维英生成应收记录（施维英此处功能为赠送出库）
     *
     * @return
     */
    private boolean needGenArap(String orgId) {
        CompanyInfoVO infoVO = companyInfoService.info(orgId);
        if (null == infoVO) {
            return false;
        }
        return (infoVO.getIsSap() != null && infoVO.getIsSap() == 0)
                || CompanyUtil.isSWY(infoVO.getSapCode());
    }

    public void balanceAdd(SalesOutBillDO salesOutBillDO, String orgId) throws Exception {
        Short billType = salesOutBillDO.getBillType();
        if (SaleOutEnum.SaleBillTypeThreePack.getCode() == billType) {
            return;
        }
        SalesBillDO salesBillDO = salesBillMapper.selectBySalesBillNo(salesOutBillDO.getSalesBillNo());
        if (null == salesBillDO) {
            throw new Exception("销售单信息不存在");
        }
        //生成应收记录
        CompanyDealerDO dealerDO = companyDealerMapper.getDealer(orgId, salesBillDO.getClientId());
        if (null == dealerDO) {
            throw new Exception("客户信息不存在");
        }
        ArapDO arapDO = arapMapper.selectByAccOrgId(orgId, dealerDO.getDealerOrgId(), 0);
        if (arapDO == null) {
            arapDO = new ArapDO();
            arapDO.setId(fastGenClient.newGuidText().getValue());
            arapDO.setOrgId(orgId);
            arapDO.setAccOrgId(dealerDO.getDealerOrgId());
            arapDO.setAccOrgName(salesOutBillDO.getClientName());
            arapDO.setDealerCode(dealerDO.getDealerCode());
            arapDO.setArapType(0);
            arapDO.setReceiverPrice(salesOutBillDO.getTotalPrice());
            arapDO.setCreateDate(new Date());
            int insert = arapMapper.insert(arapDO);
            if (insert <= 0) {
                throw new Exception("生成应收记录失败");
            }
        } else {
            arapDO.setOldReceiverPrice(arapDO.getReceiverPrice());
            arapDO.setReceiverPrice(arapDO.getReceiverPrice().add(salesOutBillDO.getTotalPrice()));
            arapDO.setUpdateDate(new Date());
            int updateCount = arapMapper.updateSelective(arapDO);
            if (updateCount <= 0) {
                throw new Exception("生成应收记录失败");
            }
        }

        ArapDetailDO arapDetailDO = arapDetailMapper.selectByBillNo(orgId, salesOutBillDO.getSalesOutBillNo());
        if (arapDetailDO == null) {
            arapDetailDO = new ArapDetailDO();
            arapDetailDO.setId(fastGenClient.newGuidText().getValue());
            arapDetailDO.setSupplierOrgId(orgId);
            String createId = salesOutBillDO.getCreateId();
            CompanyInfoVO companyInfoVO = companyInfoService.querySelfCompanyInfo(createId);
            if (null != companyInfoVO) {
                arapDetailDO.setSupplierOrgName(companyInfoVO.getCompanyName());
            }
            arapDetailDO.setPurchaseOrgId(dealerDO.getDealerOrgId());
            arapDetailDO.setPurchaseOrgName(dealerDO.getCompanyName());
            arapDetailDO.setDeliveryOutNo(genDocumentService.getDeliveryNo());
            arapDetailDO.setBillId(salesOutBillDO.getId());
            arapDetailDO.setBillNo(salesOutBillDO.getSalesOutBillNo());
            arapDetailDO.setBillDate(salesOutBillDO.getCreateDate());
            arapDetailDO.setBillSingle(StringUtils.left(salesOutBillDO.getSalesOutBillNo(), 4));
            arapDetailDO.setTotalPrice(salesOutBillDO.getTotalPrice());
            arapDetailDO.setRemainPrice(salesOutBillDO.getTotalPrice());
            arapDetailDO.setCreateDate(new Date());
            arapDetailDO.setSaleBillType(salesOutBillDO.getBillType().intValue());
            int insert = arapDetailMapper.insert(arapDetailDO);
            if (insert <= 0) {
                throw new Exception("生成应收详情记录失败");
            }
        }
    }

    private void updateOutboundStatusAndQty(SalesOutBillVO headerInfo, SalesOutBillDetailDO detailDO) throws Exception {
        String borrowBillNo = headerInfo.getBorrowBillNo();
        if (detailDO.getIsState() != 1 || StringUtils.isBlank(borrowBillNo)) {
            return;
        }
        SalesBillDetailDO salesBillDetailDO = salesBillDetailMapper.getInfoByBillNoMate(detailDO.getSalesBillNo(), detailDO.getMaterialNo());
        BigDecimal actualOutboundQty = salesBillDetailDO.getActualOutboundQty() == null ? BigDecimal.ZERO : salesBillDetailDO.getActualOutboundQty();
        SalesBillDetailDO updateDetailDO = new SalesBillDetailDO();
        updateDetailDO.setMaterialNo(detailDO.getMaterialNo());
        updateDetailDO.setSalesBillNo(detailDO.getSalesBillNo());
        BigDecimal outboundQty = actualOutboundQty.add(detailDO.getThisShipQty());
        if (outboundQty.compareTo(salesBillDetailDO.getApplyQty()) == 0) {
            updateDetailDO.setOutboundStatus(2);
        } else {
            updateDetailDO.setOutboundStatus(1);
        }
        updateDetailDO.setActualOutboundQty(outboundQty);
        int updateCount = salesBillDetailMapper.updateCreateOutQty(updateDetailDO);
        if (updateCount <= 0) {
            throw new Exception("新增销售出库单失败");
        }
        Integer outboundStatusCount = salesBillDetailMapper.checkOutboundStatus(detailDO.getSalesBillNo());
        SalesBillDO record = new SalesBillDO();
        record.setOutboundStatus(1);
        if (outboundStatusCount <= 0) {
            record.setOutboundStatus(2);
        }
        record.setSalesBillNo(detailDO.getSalesBillNo());
        record.setOutboundDate(new Date());
        int updateSalesBillCount = salesBillMapper.updateBySalesBillNo(record);
        if (updateSalesBillCount <= 0) {
            throw new Exception("新增销售出库单失败");
        }
    }

    //更新服务人员额度
    private boolean updateQuota(SalesOutBillVO headerInfo, SalesOutBillDetailDO detailDO) throws Exception {
        String borrowBillNo = headerInfo.getBorrowBillNo();
        if (detailDO.getIsState() == 0 || StringUtils.isBlank(borrowBillNo)) {
            return false;
        }
        //校验服务人员状态

        String salesBillNo = detailDO.getSalesBillNo();
        SalesBillDO salesBillDO = salesBillMapper.selectBySalesBillNo(salesBillNo);
        if (null == salesBillDO) {
            return true;
        }
        String servicePersonId = salesBillDO.getServicePersonId();
        Integer countIsDisable = serviceStaffQuotaService.countIsDisable(servicePersonId);
        if (countIsDisable <= 0) {
            return false;
        }
        BigDecimal singlePrice = detailDO.getSinglePrice();
        BigDecimal outQuota = detailDO.getThisShipQty().multiply(singlePrice).setScale(2, BigDecimal.ROUND_DOWN);
        ServiceStaffQuotaUseVO serviceStaffQuotaUseVO = new ServiceStaffQuotaUseVO();
        serviceStaffQuotaUseVO.setStaffName(salesBillDO.getServicePersonName());
        serviceStaffQuotaUseVO.setStaffId(servicePersonId);
        serviceStaffQuotaUseVO.setBorrowedAmount(CalcUtil.subtract(BigDecimal.ZERO, outQuota));
        serviceStaffQuotaUseVO.setPendingPayment(outQuota);
        ErrorCode errorCode = serviceStaffQuotaService.useQuotaSubtract(serviceStaffQuotaUseVO);
        return ErrorCode.Success != errorCode;
    }

    private void updateOrderStatus(SalesOutBillDetailVO detailVO, SalesOutBillDetailDO detailDO, String orgId) throws Exception {
        if (detailDO.getIsState() == 1) {
            // 校验提交的数量与订单数量比较
            BigDecimal totalOrderQty = salesOutBillDetailMapper.getTotalOrderQty(detailDO.getSalesBillNo(), detailDO.getMaterialNo());
            BigDecimal createOutBillTotal = salesOutBillDetailMapper.getCreateOutBillTotal(detailDO.getSalesBillNo(), detailDO.getMaterialNo());
            if (null != totalOrderQty && null != createOutBillTotal &&
                    createOutBillTotal.add(detailVO.getThisShipQty()).setScale(4, BigDecimal.ROUND_DOWN).compareTo(totalOrderQty) > 0) {
                throw new Exception("提交本次发货数量大于订单总数，提交失败");
            }
            //更新销售单状态
            createOutBillTotal = createOutBillTotal == null ? BigDecimal.ZERO : createOutBillTotal;
            BigDecimal outboundTotalQty = createOutBillTotal.add(detailVO.getThisShipQty()).setScale(4, BigDecimal.ROUND_DOWN);
            boolean success = salesBillService.updateByOutBound(detailDO.getSalesBillNo(), detailDO.getMaterialNo(), orgId, detailVO.getTotalOrderQty(), outboundTotalQty);
            if (!success) {
                throw new Exception("新增销售出库单失败");
            }
        } else {
            int i = salesBillMapper.updateStatusBySalesNo(detailDO.getSalesBillNo(), 1, null);
            if (i <= 0) {
                throw new Exception("新增销售出库单失败");
            }
        }
    }

    private boolean checkOrderQty(List<SalesOutBillDetailVO> materialList) {
        for (SalesOutBillDetailVO detailVO : materialList) {
            BigDecimal issuedQty = detailVO.getIssuedQty() == null ? BigDecimal.ZERO : detailVO.getIssuedQty();//已发数量
            BigDecimal thisShipQty = detailVO.getThisShipQty(); // 本次发货数量
            BigDecimal totalOrderQty = detailVO.getTotalOrderQty(); //订单总数量
            if (null == thisShipQty || null == totalOrderQty) {
                return true;
            }
            //本次发货数量不能大于剩余数量
            if ((issuedQty.add(thisShipQty)).compareTo(totalOrderQty) > 0) {
                return true;
            }
        }
        return false;
    }

    private SalesOutBillDO getSalesOutBillDO(String userId, String orgId, String userName, String salesOutBillNo, SalesOutBillVO headerInfo) throws Exception {
        SalesOutBillDO salesOutBillDO = new SalesOutBillDO();
        String id = fastGenClient.newGuidText().getValue();
        if (StringUtils.isBlank(id)) {
            throw new Exception("新增销售出库单失败");
        }
        salesOutBillDO.setId(id);
        salesOutBillDO.setBillType(headerInfo.getBillType());
        salesOutBillDO.setCheckState((short) 0);
        if (SaleOutEnum.SaleBillTypeThreePack.getCode() == headerInfo.getBillType()) {
            salesOutBillDO.setCheckState((short) 2);
        }
        salesOutBillDO.setBorrowBillNo(headerInfo.getBorrowBillNo());
        salesOutBillDO.setClientName(headerInfo.getClientName());
        salesOutBillDO.setConsignee(headerInfo.getConsignee());
        salesOutBillDO.setContactPhone(headerInfo.getContactPhone());
        salesOutBillDO.setCreateDate(new Date());
        salesOutBillDO.setCreateId(userId);
        salesOutBillDO.setGenerateDate(headerInfo.getGenerateDate());
        salesOutBillDO.setGeneratePerson(userName);
        salesOutBillDO.setIsState((short) 0);
        salesOutBillDO.setOrgId(orgId);
        salesOutBillDO.setOutArea(headerInfo.getOutArea());
        salesOutBillDO.setOutboundStatus((short) 0);
        salesOutBillDO.setReceiptAddress(headerInfo.getReceiptAddress());
        salesOutBillDO.setRemark(headerInfo.getRemark());
        salesOutBillDO.setSalesBillNo(headerInfo.getSalesBillNo());
        salesOutBillDO.setSalesOutBillNo(salesOutBillNo);
        salesOutBillDO.setServicePersonName(headerInfo.getServicePersonName());
        salesOutBillDO.setTotalPrice(headerInfo.getTotalPrice());
        salesOutBillDO.setUpdateDate(new Date());
        salesOutBillDO.setUpdateId(userId);
        salesOutBillDO.setCostTotal(headerInfo.getCostTotal());
        return salesOutBillDO;
    }

    private SalesOutBillDetailDO getSalesOutBillDetailDO(String userId, String orgId, String salesOutBillNo,
                                                         SalesOutBillVO headerInfo, SalesOutBillDetailVO detailVO, String detailId, Integer status) {
        SalesOutBillDetailDO detailDO = new SalesOutBillDetailDO();
        if (status == 0) {
            detailDO.setIsState((short) 0);
        } else {
            detailDO.setIsState((short) 1);
        }
        detailDO.setId(detailId);
        detailDO.setSalesBillOutNo(salesOutBillNo);
        detailDO.setSalesBillNo(headerInfo.getSalesBillNo());
        detailDO.setMaterialNo(detailVO.getMaterialNo());
        detailDO.setMaterialDes(detailVO.getMaterialDes());
        detailDO.setCreateDate(new Date());
        detailDO.setCreateId(userId);
        detailDO.setDefaultStorage(detailVO.getLocationCode());
        detailDO.setIntentOccupation(detailVO.getIntentOccupation());
        detailDO.setIssuedQty(detailVO.getIssuedQty());
        detailDO.setOnlineStock(detailVO.getOnlineStock());
        detailDO.setOrgId(orgId);
        detailDO.setOutboundQty(detailVO.getOutboundQty());
        String borrowBillNo = headerInfo.getBorrowBillNo();
        detailDO.setOutboundStatus((short) 0);
        if (status == 1 && StringUtils.isNotBlank(borrowBillNo)) {
            detailDO.setOutboundStatus((short) 2);
            detailDO.setOutboundQty(detailVO.getThisShipQty());
        }
        detailDO.setRealStockQty(detailVO.getRealStockQty());
        detailDO.setSafetyStock(detailVO.getSafetyStock());
        detailDO.setShipOccupation(detailVO.getShipOccupation());
        detailDO.setSinglePrice(detailVO.getSinglePrice());
        detailDO.setThisShipQty(detailVO.getThisShipQty());
        detailDO.setTotalOrderQty(detailVO.getTotalOrderQty());
        detailDO.setUnit(detailVO.getUnit());
        detailDO.setUpdateDate(new Date());
        detailDO.setUpdateId(userId);
        detailDO.setCostPrice(detailVO.getCostPrice());
        detailDO.setCostSubtotal(detailVO.getCostSubtotal());
        return detailDO;
    }

    /**
     * 修改销售出库单
     *
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public synchronized ErrorCode update(SaleOutAddVO addVO, String userId, String orgId) throws Exception {
        List<DeliveryNoteDetailVO> deliveryNoteDetailVOList = new ArrayList<>();
        SalesOutBillVO headerInfo = addVO.getHeaderInfo();
        Integer status = addVO.getStatus();
        List<SalesOutBillDetailVO> materialList = addVO.getMaterialList();
        boolean result = checkOrderQty(materialList);
        if (result) {
            return ErrorCode.DeliveryNoteQtyError;
        }
        // 校验单据状态是否允许修改
        String salesOutBillNo = headerInfo.getSalesOutBillNo();
        List<SalesOutBillDetailDO> detailDOList = salesOutBillDetailMapper.selectBySalesOutBillNo(salesOutBillNo);

        BigDecimal totalCostPrice = BigDecimal.ZERO;
        BigDecimal totalPrice = BigDecimal.ZERO;
        salesOutBillDetailMapper.deleteBySalesOutBillNo(salesOutBillNo);
        for (SalesOutBillDetailVO detailVO : materialList) {
            String detailId = fastGenClient.newGuidText().getValue();
            if (StringUtils.isBlank(detailId)) {
                throw new Exception("修改销售出库单失败");
            }
            SalesOutBillDetailDO detailDO = getSalesOutBillDetailDO(userId, orgId, salesOutBillNo, headerInfo, detailVO, detailId, status);
            boolean updateQuota = updateQuota(headerInfo, detailDO);
            if (updateQuota) {
                throw new Exception("扣减服务人员额度失败");
            }

            //借用单转销售 更新出库状态与出库数量
            updateOutboundStatusAndQty(headerInfo, detailDO);

            updateOrderStatus(detailVO, detailDO, orgId);
            int insCount = salesOutBillDetailMapper.insertSelective(detailDO);
            if (insCount <= 0) {
                throw new Exception("修改销售出库单失败");
            }
            BigDecimal costPrice = detailDO.getCostPrice() == null ? BigDecimal.ZERO : detailDO.getCostPrice();
            BigDecimal thisShipQty = detailDO.getThisShipQty() == null ? BigDecimal.ZERO : detailDO.getThisShipQty();
            totalCostPrice = totalCostPrice.add(costPrice.multiply(thisShipQty));
            totalPrice = totalPrice.add(detailDO.getSinglePrice().multiply(thisShipQty));

            DeliveryNoteDetailVO deliveryNoteDetailVO = new DeliveryNoteDetailVO();
            deliveryNoteDetailVO.setMaterialsNo(detailDO.getMaterialNo());
            deliveryNoteDetailVO.setMaterialsDes(detailDO.getMaterialDes());
            deliveryNoteDetailVO.setUnit(detailDO.getUnit());
            deliveryNoteDetailVO.setDeliveryQty(detailDO.getThisShipQty());
            deliveryNoteDetailVOList.add(deliveryNoteDetailVO);
            if (detailDO.getIsState() == 1) { // 提交状态更新销售单创建状态。与创建数量
                Optional<SalesOutBillDetailDO> tempDO = detailDOList.stream().filter(x -> x.getMaterialNo().equals(detailDO.getMaterialNo()) && x.getIsState() == 1).findFirst();
                BigDecimal oldThisShipQty = BigDecimal.ZERO;
                if (tempDO.isPresent()) {
                    oldThisShipQty = tempDO.get().getThisShipQty();
                }
                boolean updateResult = salesBillService.updateCreateOutStatus(detailDO.getSalesBillNo(), detailDO.getMaterialNo(),
                        detailDO.getThisShipQty(), null, oldThisShipQty, null);
                if (!updateResult) {
                    throw new Exception("修改销售出库单失败");
                }
            }
        }

        headerInfo.setCostTotal(totalCostPrice);
        headerInfo.setTotalPrice(totalPrice);
        SalesOutBillDO salesOutBillDO = getUpdateSalesOutBillDO(userId, headerInfo);
        if (status == 0) {//保存
            int insSalesOutCount = salesOutBillMapper.updateByPrimaryKeySelective(salesOutBillDO);
            if (insSalesOutCount <= 0) {
                throw new Exception("修改销售出库单失败");
            }
        } else {// 提交
            salesOutBillDO.setIsState((short) 1);
            if (StringUtils.isNotBlank(salesOutBillDO.getBorrowBillNo())) {
                salesOutBillDO.setOutboundStatus((short) 2);
                salesOutBillDO.setOutboundDate(new Date());
            }
            int insSalesOutCount = salesOutBillMapper.updateByPrimaryKeySelective(salesOutBillDO);
            if (insSalesOutCount <= 0) {
                throw new Exception("修改销售出库单失败");
            }

            if (salesOutBillDO.getOutboundStatus() != 2) {
                // 新增出库单时新增发货事物单
                DeliveryNoteAddVO deliveryNoteAddVO = new DeliveryNoteAddVO();
                DeliveryNoteVO deliveryNoteVO = new DeliveryNoteVO();
                deliveryNoteVO.setDeliveryNo(salesOutBillNo);
                // deliveryNoteVO.setOutArea(headerInfo.getOutArea());
                deliveryNoteVO.setOutLocation(headerInfo.getOutArea());
                deliveryNoteAddVO.setHeaderInfo(deliveryNoteVO);
                deliveryNoteAddVO.setMaterialList(deliveryNoteDetailVOList);
                //先删除由提交状态变成保存状态的事物表数据
                warehouseDeliveryService.removeByBusinessOrders(Collections.singletonList(salesOutBillNo), orgId);
                warehouseDeliveryService.saveByDeliveryNoteOut(deliveryNoteAddVO, userId, orgId);
            }

            if (needGenArap(orgId)) {
                this.balanceAdd(salesOutBillDO, orgId);
            }
        }
        return ErrorCode.Success;
    }

    private SalesOutBillDO getUpdateSalesOutBillDO(String userId, SalesOutBillVO headerInfo) {
        SalesOutBillDO salesOutBillDO = new SalesOutBillDO();
        salesOutBillDO.setId(headerInfo.getId());
        salesOutBillDO.setBorrowBillNo(headerInfo.getBorrowBillNo());
        salesOutBillDO.setClientName(headerInfo.getClientName());
        salesOutBillDO.setConsignee(headerInfo.getConsignee());
        salesOutBillDO.setContactPhone(headerInfo.getContactPhone());
        salesOutBillDO.setIsState((short) 0);
        salesOutBillDO.setOutArea(headerInfo.getOutArea());
        salesOutBillDO.setReceiptAddress(headerInfo.getReceiptAddress());
        salesOutBillDO.setRemark(headerInfo.getRemark());
        salesOutBillDO.setTotalPrice(headerInfo.getTotalPrice());
        salesOutBillDO.setUpdateDate(new Date());
        salesOutBillDO.setUpdateId(userId);
        salesOutBillDO.setCostTotal(headerInfo.getCostTotal());
        salesOutBillDO.setOutboundStatus((short) 0);
        salesOutBillDO.setSalesBillNo(headerInfo.getSalesBillNo());
        salesOutBillDO.setSalesOutBillNo(headerInfo.getSalesOutBillNo());
        salesOutBillDO.setBillType(headerInfo.getBillType());
        salesOutBillDO.setCreateDate(headerInfo.getCreateDate());
        if (SaleOutEnum.SaleBillTypeThreePack.getCode() == headerInfo.getBillType()) {
            salesOutBillDO.setCheckState((short) 2);
        }
        return salesOutBillDO;
    }

    public SaleOutAddVO itemBySaleBillNo(String saleBillNo, String orgId) {
        List<SalesOutBillDetailVO> materialList = new ArrayList<>();
        List<SalesBillDetailDO> billDetailDOList = salesBillDetailMapper.selectBySalesBillNo(saleBillNo);
        for (SalesBillDetailDO salesBillDetailDO : billDetailDOList) {
            //判断此零件是否存在可出库数量，根据出库单详情中生效的零件建出库单总数
            String materialNo = salesBillDetailDO.getMaterialNo();
            String salesBillNo = salesBillDetailDO.getSalesBillNo();
            BigDecimal totalOrderQty = salesOutBillDetailMapper.getTotalOrderQty(salesBillNo, materialNo);
            BigDecimal createOutBillTotal = salesOutBillDetailMapper.getCreateOutBillTotal(salesBillNo, materialNo);
            if (null != totalOrderQty && null != createOutBillTotal && totalOrderQty.compareTo(createOutBillTotal) == 0) {
                continue;
            }

            SalesOutBillDetailVO detailVO = new SalesOutBillDetailVO();
            detailVO.setMaterialDes(salesBillDetailDO.getMaterialDes());
            detailVO.setMaterialNo(materialNo);
            detailVO.setUnit(salesBillDetailDO.getUnit());
            if (null == salesBillDetailDO.getApplyQty()) {
                continue;
            }
            detailVO.setTotalOrderQty(salesBillDetailDO.getApplyQty());
            //获取已发送数量
            detailVO.setIssuedQty(createOutBillTotal == null ? BigDecimal.ZERO : createOutBillTotal);
            detailVO.setThisShipQty(detailVO.getTotalOrderQty().subtract(detailVO.getIssuedQty()));
            detailVO.setSinglePrice(salesBillDetailDO.getAdjustedSinglePrice());
            detailVO.setCostPrice(salesBillDetailDO.getCostPrice());
            detailVO.setCostSubtotal(salesBillDetailDO.getCostSubtotal());

            EnableAndOccupyVO enableAndOccupyVO = warehouseInventoryService.findEnableAndOccupyNum(materialNo, orgId, null);
            if (enableAndOccupyVO != null) {
                detailVO.setRealStockQty(enableAndOccupyVO.getEnableNum());
                detailVO.setIntentOccupation(enableAndOccupyVO.getIntentionNum());
                detailVO.setShipOccupation(enableAndOccupyVO.getDeliveryNum());
            }

            PriMaterialsDO resouce = priMaterialsMapper.itemByNo(materialNo, orgId);
            if (null != resouce) {
                detailVO.setSafetyStock(resouce.getSafeAmount());
                detailVO.setOnlineStock(resouce.getMaxAmount());
            }

            MaterialLocationRelationVO materialLocationRelationVO = new MaterialLocationRelationVO();
            materialLocationRelationVO.setMaterialNo(detailVO.getMaterialNo());
            materialLocationRelationVO.setOrgId(orgId);
            List<MaterialLocationRelationVO> voList = materialLocationRelationMapper.list(materialLocationRelationVO);
            detailVO.setStockLocationList(voList);
            if (voList == null || voList.size() <= 0) {
                detailVO.setStockLocation("暂无默认储位");
            }

            materialList.add(detailVO);
        }
        SaleOutAddVO result = new SaleOutAddVO();
        result.setMaterialList(materialList);
        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    public ErrorCode remove(List<String> ids, String orgId) throws Exception {
        for (String id : ids) {
            // 判断是否允许删除
            int count = salesOutBillMapper.checkOutStatus(id);
            if (count <= 0) {
                return ErrorCode.AbnormalOutDeleteError;
            }
        }
        CompanyInfoVO infoVO = companyInfoService.info(orgId);
        for (String id : ids) {
            SalesOutBillDO salesOutBillDO = salesOutBillMapper.selectByPrimaryKey(id);
            boolean updateResult = salesBillService.updateCreateOutQty(salesOutBillDO.getSalesOutBillNo(), null, true, false);
            if (!updateResult) {
                throw new Exception(ErrorCode.Failure.getDesc());
            }

            ErrorCode errorCode = warehouseDeliveryService.removeByBusinessOrders(Collections.singletonList(salesOutBillDO.getSalesOutBillNo()), orgId);
            int delDetailCount = salesOutBillDetailMapper.deleteBySalesOutBillNo(salesOutBillDO.getSalesOutBillNo());
            if (delDetailCount <= 0) {
                throw new Exception(ErrorCode.Failure.getDesc());
            }
            int delCount = salesOutBillMapper.deleteByPrimaryKey(id);
            if (delCount <= 0) {
                throw new Exception(ErrorCode.Failure.getDesc());
            }
            if (salesOutBillDO.getIsState() == 0) {
                continue;
            }
            int i = salesBillMapper.updateStatusBySalesNo(salesOutBillDO.getSalesBillNo(), 1, null);
            if (i <= 0) {
                throw new Exception(ErrorCode.Failure.getDesc());
            }

            if (needUpdateArap(orgId)) {
                // 删除应收记录详情，修改应收记录的应收金额
                delUpdateArapInfo(orgId, salesOutBillDO);
            }

        }

        return ErrorCode.Success;
    }

    /**
     * 2019-12-04 判断是否需要修改应收记录
     * 代理商+施维英删除后需要修改应收
     *
     * @param orgId
     * @return
     */
    private boolean needUpdateArap(String orgId) {
        CompanyInfoVO infoVO = companyInfoService.info(orgId);
        if (null == infoVO) {
            return false;
        }
        return (infoVO.getIsSap() != null && infoVO.getIsSap() == 0) || CompanyUtil.isSWY(infoVO.getSapCode());
    }

    // 删除应收记录详情，修改应收记录的应收金额
    private void delUpdateArapInfo(String orgId, SalesOutBillDO salesOutBillDO) throws Exception {
        if (SaleOutEnum.SaleBillTypeThreePack.getCode() == salesOutBillDO.getBillType() || 1 != salesOutBillDO.getIsState()) {
            return;
        }

        ArapDetailDO arapDetailDO = arapDetailMapper.selectByBillNo(orgId, salesOutBillDO.getSalesOutBillNo());
        if (null == arapDetailDO) {
            return;
        }

        int delArapDetailCount = arapDetailMapper.updateDelById(arapDetailDO.getId());
        if (delArapDetailCount <= 0) {
            throw new Exception("删除应收记录详情失败");
        }

        ArapDO arapDO = arapMapper.selectByAccOrgId(orgId, arapDetailDO.getPurchaseOrgId(), 0);
        if (arapDO == null) {
            throw new Exception("应收记录信息不存在");
        }

        arapDO.setOldReceiverPrice(arapDO.getReceiverPrice());
        arapDO.setReceiverPrice(arapDO.getReceiverPrice().subtract(arapDetailDO.getTotalPrice()));
        arapDO.setUpdateDate(new Date());
        int updateCount = arapMapper.updateSelective(arapDO);
        if (updateCount <= 0) {
            throw new Exception("修改应收记录中应收金额有误");
        }
    }

    public PageCommonVO list(SearchCommonVO<SalesOutBillVO> condition) {
        PageHelperPlus.orderBy("create_date desc");
        PageHelperPlus.startPage(condition.getPageNum(), condition.getPageSize());
        List<SalesOutBillDO> billDOList = salesOutBillMapper.list(condition.getFilters());

        /**
         * upd by wxd
         * 增加退货单号查询
         */
        List<String> saleOutIdList = billDOList.stream().map(SalesOutBillDO::getId).collect(Collectors.toList());

        Map<String, AgentReturnDO> returnDOMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(saleOutIdList)) {
            //根据销售出库单号查询退货单号
            List<AgentReturnDO> returnDOList = agentReturnDOMapper.selectBySaleOutIds(saleOutIdList);
            if (CollectionUtils.isNotEmpty(returnDOList)) {
                //获取销售出库-->退货单map
                returnDOMap = returnDOList.stream().collect(Collectors.toMap(AgentReturnDO::getSaleOutId, Function.identity(), (k1, k2) -> k1));
            }
        }

        List<SalesOutBillVO> voList = new ArrayList<>();
        for (SalesOutBillDO salesOutBillDO : billDOList) {
            Short billType = salesOutBillDO.getBillType();
            SalesOutBillVO model = new SalesOutBillVO();
            BeanUtils.copyProperties(salesOutBillDO, model);
            String salesBillNo = salesOutBillDO.getSalesBillNo();
            SalesBillDO salesBillDO = salesBillMapper.selectBySalesBillNo(salesBillNo);
            if (null != salesBillDO) {
                model.setPurchaseOrgId(salesBillDO.getClientId());
            }
            model.setTotalDiscountPrice(BigDecimal.ZERO);
            if (SaleOutEnum.SaleBillTypeThreePack.getCode() != billType) {
                // 获取结算总金额
                BigDecimal settlementAmount = getSettlementAmount(salesOutBillDO, condition.getFilters().getOrgId());
                model.setTotalDiscountPrice(settlementAmount);
            }
            //设置退货单号
            if (null != returnDOMap.get(salesOutBillDO.getId())) {
                model.setReturnNo(returnDOMap.get(salesOutBillDO.getId()).getReturnNo());//退货单号
                model.setReturnId(returnDOMap.get(salesOutBillDO.getId()).getId());//退货单id
            }
            // 过账信息
//            try {
//                SalesOutPostDO salesOutPostDO = salesOutPostMapper.getByOutId(salesOutBillDO.getId());
//                if (null != salesOutPostDO) {
//                    model.setMaterialsNo(salesOutPostDO.getMaterialsNo());
//                    model.setSapSaleOrder(salesOutPostDO.getSapSaleOrder());
//                }
//            } catch (Exception e) {
//                LogHelper.monitor("SalesBillOutService#list#salesOutPostDO is error");
//            }

            voList.add(model);
        }
        PageCommonVO<SalesOutBillVO> result = new PageCommonVO<>();
        result.setPageInfo(new PageInfo<>(billDOList));
        result.setPageInfoList(voList);
        return result;
    }

    private BigDecimal getSettlementAmount(SalesOutBillDO salesOutBillDO, String orgId) {
        BigDecimal totalPrice = BigDecimal.ZERO;
        List<SalesOutBillDetailDO> detailDOS = salesOutBillDetailMapper.selectBySalesOutBillNo(salesOutBillDO.getSalesOutBillNo());
        if (detailDOS.isEmpty()) {
            return totalPrice;
        }
        for (SalesOutBillDetailDO detailDO : detailDOS) {
            if (3 == detailDO.getOutboundStatus()) {
                totalPrice = totalPrice.add(detailDO.getOutboundQty().multiply(detailDO.getSinglePrice()));
            } else {
                totalPrice = totalPrice.add(detailDO.getThisShipQty().multiply(detailDO.getSinglePrice()));
            }
        }
        // 获取欠款金额
        ArapDetailDO arapDetailDO = arapDetailMapper.selectByBillNo(orgId, salesOutBillDO.getSalesOutBillNo());
        if (null != arapDetailDO) {
            BigDecimal receivePrice = arapDetailDO.getReceivePrice();
            totalPrice = totalPrice.subtract(receivePrice == null ? BigDecimal.ZERO : receivePrice);
        }
        totalPrice = totalPrice.setScale(2, BigDecimal.ROUND_HALF_DOWN);
        return totalPrice.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : totalPrice;
    }

    public SaleOutAddVO item(String id, boolean isPrint, CompanyInfoDO company) {
        String orgId = company.getOrgId();
        SaleOutAddVO result = new SaleOutAddVO();
        SalesOutBillDO salesOutBillDO = salesOutBillMapper.selectByPrimaryKey(id);
        if (salesOutBillDO == null) {
            return result;
        }
        SalesOutBillVO salesOutBillVO = new SalesOutBillVO();
        BeanUtils.copyProperties(salesOutBillDO, salesOutBillVO);
        salesOutBillVO.setOrgCode(company.getOrgCode());
        String salesBillNo = salesOutBillDO.getSalesBillNo();
        SalesBillDO salesBillDO = salesBillMapper.selectBySalesBillNo(salesBillNo);
        if (null != salesBillDO) {
            salesOutBillVO.setUseMachineNo(salesBillDO.getUseMachineNo());
            salesOutBillVO.setSettleMachineNo(salesBillDO.getSettleMachineNo());
            //进出口查询自己代理商；海外代理商查询进出口端设置税率
            CompanyDealerDO dealerDO = new CompanyDealerDO();
            if (StringUtils.isNotEmpty(company.getSapCode()) && CompanyUtil.JCK_SAP_CODE.equals(company.getSapCode())) {//进出口
                String clientId = salesBillDO.getClientId();
                if (StringUtils.isNotEmpty(clientId)) {
                    dealerDO = companyDealerMapper.getDealer(orgId, clientId);
                }
            } else {//海外客户
                CompanyInfoDO companyInfoDO = companyInfoMapper.itemBySap(CompanyUtil.JCK_SAP_CODE);
                if (null != companyInfoDO) {
                    dealerDO = companyDealerMapper.getDealerByPlatOrgId(companyInfoDO.getOrgId(), orgId);
                }
            }

            BigDecimal taxRate = dealerDO == null ? null : dealerDO.getTaxRate();
            BigDecimal totalPrice = salesOutBillDO.getTotalPrice();
            totalPrice = taxRate == null ? totalPrice : DecimalUtil.getDecimal(taxRate).multiply(DecimalUtil.getDecimal(totalPrice));
            salesOutBillVO.setVat(totalPrice);

        }

        if (isPrint && salesOutBillDO.getIsPrint() == 0) {
            SalesOutBillDO salesOutBillDO1 = new SalesOutBillDO();
            salesOutBillDO1.setIsPrint((short) 1);
            salesOutBillDO1.setId(salesOutBillDO.getId());
            salesOutBillMapper.updateByPrimaryKeySelective(salesOutBillDO1);
        }
        if (StringUtils.isNotBlank(salesOutBillVO.getOutArea())) {
            WarehouseDO warehouse = warehouseDOMapper.itemByWarehouseCode(orgId, salesOutBillVO.getOutArea());
            if (null != warehouse) {
                salesOutBillVO.setWarehouseCodeDesc(warehouse.getDescription());
            }
        }
        result.setHeaderInfo(salesOutBillVO);
        List<SalesOutBillDetailVO> listVO = new ArrayList<>();
        List<SalesOutBillDetailDO> detailDOList = salesOutBillDetailMapper.selectBySalesOutBillNo(salesOutBillDO.getSalesOutBillNo());
        detailDOList.forEach(x -> {
            SalesOutBillDetailVO salesBillDetailVO = new SalesOutBillDetailVO();
            BeanUtils.copyProperties(x, salesBillDetailVO);
            // 获取默认储位
            String defaultStorage = x.getDefaultStorage();
            if (StringUtils.isNotBlank(defaultStorage)) {
                salesBillDetailVO.setLocationCode(defaultStorage);
            } else {
                getDefaultLocationCode(orgId, salesOutBillVO, salesBillDetailVO);
            }
            String loactionCode = salesBillDetailVO.getLocationCode();
            if (StringUtils.isNotBlank(loactionCode)) {
                salesBillDetailVO.setLocationDesc(warehouseAreaLocationDOMapper.getLocationDesc(loactionCode));
            }
            //如果时打印操作，则需要显示英文描述
            if (isPrint) {
                String materialDes = x.getMaterialDes();
                String materialNo = x.getMaterialNo();
                String materialsDescEn = getMaterialsDescEn(materialDes, materialNo);
                salesBillDetailVO.setMaterialsDescEn(materialsDescEn);
            }
            BigDecimal amount = DecimalUtil.getDecimal(salesBillDetailVO.getSinglePrice()).multiply(salesBillDetailVO.getThisShipQty()).setScale(2, BigDecimal.ROUND_HALF_DOWN);
            BigDecimal actualReturnQty = salesBillDetailVO.getActualReturnQty();
            BigDecimal remainReturnQty = salesBillDetailVO.getOutboundQty().subtract(actualReturnQty);
            salesBillDetailVO.setRemainReturnQty(remainReturnQty);
            salesBillDetailVO.setAmount(amount);
            listVO.add(salesBillDetailVO);
        });
        result.setMaterialList(listVO);
        return result;
    }

    private String getMaterialsDescEn(String materialsDesc, String materialsNo) {
        PubMaterialsDO pubMaterialsDO = pubMaterialsMapper.itemByMaterialsNo(materialsNo);
        String materialsDesEn = null;
        if (pubMaterialsDO == null || StringUtils.isEmpty(pubMaterialsDO.getMaterialsDesEn())) {
            BaiduTranslateResultDO baiduTranslateResultDO = baiduApiService.materialsDescTranslate(materialsDesc);
            ErrorCode errorCode = baiduTranslateResultDO.getErrorCode();
            if (errorCode != null && errorCode.getCode() == ErrorCode.Success.getCode()) {
                materialsDesEn = baiduTranslateResultDO.getTranslateResult();
                if (pubMaterialsDO == null) {
                    try {
                        pubMaterialsDO = new PubMaterialsDO();
                        pubMaterialsDO.setMaterialsNo(materialsNo);
                        pubMaterialsDO.setMaterialsDesEn(materialsDesEn);
                        pubMaterialsDO.setCreateDate(new Date());
                        pubMaterialsMapper.insertMaterialsLocal(pubMaterialsDO);
                    } catch (Exception e) {
                        LogHelper.monitor("保存英文描述失败");
                    }
                } else {
                    try {
                        pubMaterialsDO.setMaterialsDesEn(materialsDesEn);
                        pubMaterialsDO.setUpdateDate(new Date());
                        pubMaterialsMapper.updateMaterialsLocal(pubMaterialsDO);
                    } catch (Exception e) {
                        LogHelper.monitor("更新英文描述失败");
                    }
                }
            }
        } else {
            materialsDesEn = pubMaterialsDO.getMaterialsDesEn();
        }
        return materialsDesEn;
    }

    // 获取默认储位
    private void getDefaultLocationCode(String orgId, SalesOutBillVO vo, SalesOutBillDetailVO detailVO) {
        MaterialLocationRelationVO condition = new MaterialLocationRelationVO();
        condition.setWarehouseCode(vo.getOutArea());
        condition.setOrgId(orgId);
        condition.setMaterialNo(detailVO.getMaterialNo());
        List<MaterialLocationRelationVO> voList = materialLocationRelationMapper.list(condition);
        if (!voList.isEmpty()) {
            detailVO.setLocationCode(voList.get(0).getLocationCode());
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public ErrorCode manualFinish(String salesOutBillNo, String materialsNo, String orgId) throws Exception {
        SalesOutBillDO salesOutBillDO = salesOutBillMapper.selectBySalesOutBillNo(salesOutBillNo);
        if (salesOutBillDO == null) {
            return ErrorCode.IllegalArument;
        }
        if (salesOutBillDO.getIsState() == 0) {
            return ErrorCode.NotFinishBill;
        }

        Short checkState = salesOutBillDO.getCheckState();
        // 三包出库的单据可以结单
        if (0 != checkState && !salesOutBillDO.getBillType().equals(new Short("2"))) {
            //对配件新零售的单据不做此结单限制
            ArapDetailDO arapDetailDO = arapDetailMapper.selectByBillNo(orgId, salesOutBillNo);
            if (null != arapDetailDO) {
                return ErrorCode.SettlementDataRedemptionWhenSettlementSalesReceiptStatement;
            }
        }

        //跟新销售单创建出库单数量
        salesBillService.updateCreateOutQty(salesOutBillNo, materialsNo, false, true);
        int i = salesBillMapper.updateStatusBySalesNo(salesOutBillDO.getSalesBillNo(), 1, 1);
        if (i <= 0) {
            throw new Exception(ErrorCode.Failure.getDesc());
        }

        if (StringUtil.isNullOrEmpty(materialsNo))//零件编码为空，更新单据状态为“手动完成”
        {
            salesOutBillMapper.updateStatus(salesOutBillNo, 3, orgId, new Date());
            warehouseDeliveryService.updateState(salesOutBillNo, 3, orgId);
            salesOutBillDetailMapper.updateStatus(salesOutBillNo, 3, orgId, null);
            warehouseDeliveryDetailMapper.updateAllStatus(3, salesOutBillNo, orgId);
        } else {
            salesOutBillDetailMapper.updateStatus(salesOutBillNo, 3, orgId, materialsNo);
            warehouseDeliveryService.updateDetailState(salesOutBillNo, materialsNo, null, 3, orgId);
            ErrorCode errorCode = checkBillFinished(salesOutBillNo, salesOutBillNo, orgId);
            if (ErrorCode.Success != errorCode) {
                return errorCode;
            }
        }

        if (needUpdatePay(orgId, salesOutBillDO.getBillType())) {
            //更新应收金额
            updateReceivableAmount(salesOutBillNo, orgId, salesOutBillDO);
        }

        return ErrorCode.Success;
    }

    /**
     * 施维英或者代理商并且单据类型为2（此处直接copy修改，不知道这个2是什么）
     *
     * @param orgId
     * @param billType
     * @return
     */
    private boolean needUpdatePay(String orgId, Short billType) {
        CompanyInfoVO infoVO = companyInfoService.info(orgId);
        if (null == infoVO) {
            return false;
        }
        return ((infoVO.getIsSap() != null && infoVO.getIsSap() == 0) || CompanyUtil
                .isSWY(infoVO.getSapCode())) && !new Short("2").equals(billType);
    }

    private void updateReceivableAmount(String salesOutBillNo, String orgId, SalesOutBillDO salesOutBillDO) throws Exception {
        BigDecimal remainPrice = BigDecimal.ZERO;//结算之后应收款
        BigDecimal oldTotalPrice = BigDecimal.ZERO;//结算之前总金额
        List<SalesOutBillDetailDO> detailDOS = salesOutBillDetailMapper.selectBySalesOutBillNo(salesOutBillDO.getSalesOutBillNo());
        if (detailDOS.isEmpty()) {
            return;
        }
        for (SalesOutBillDetailDO detailDO : detailDOS) {
            if (3 == detailDO.getOutboundStatus()) {
                remainPrice = remainPrice.add(detailDO.getOutboundQty().multiply(detailDO.getSinglePrice()));
            } else {
                remainPrice = remainPrice.add(detailDO.getThisShipQty().multiply(detailDO.getSinglePrice()));
            }
            oldTotalPrice = oldTotalPrice.add(detailDO.getThisShipQty().multiply(detailDO.getSinglePrice()));
        }

        ArapDetailDO arapDetailDO = arapDetailMapper.selectByBillNo(orgId, salesOutBillNo);
        if (null == arapDetailDO) {
            return;
        }
        ArapDetailDO updateArapDetailDO = new ArapDetailDO();
        updateArapDetailDO.setRemainPrice(remainPrice);
        if (remainPrice.compareTo(BigDecimal.ZERO) == 0) {
            SalesOutBillDO record = new SalesOutBillDO();
            record.setCheckState((short) 2);
            record.setId(salesOutBillDO.getId());
            salesOutBillMapper.updateByPrimaryKeySelective(record);
            updateArapDetailDO.setIsSettle(1);
        }
        updateArapDetailDO.setTotalPrice(remainPrice);
        updateArapDetailDO.setId(arapDetailDO.getId());
        int updateCount = arapDetailMapper.update(updateArapDetailDO);
        if (updateCount <= 0) {
            throw new Exception("扣减应收款详情金额失败");
        }

        //扣减应收主表欠款金额
        ArapDO updateRecord = new ArapDO();
        ArapDO arapDO = arapMapper.selectByAccOrgId(orgId, arapDetailDO.getPurchaseOrgId(), 0);
        updateRecord.setOldReceiverPrice(arapDO.getReceiverPrice());
        updateRecord.setReceiverPrice(arapDO.getReceiverPrice().subtract(oldTotalPrice).add(remainPrice));
        updateRecord.setId(arapDO.getId());
        int updateArapCount = arapMapper.updateSelective(updateRecord);
        if (updateArapCount <= 0) {
            throw new Exception("扣减应收款欠款金额失败");
        }
    }


    public PageCommonVO availableReturnList(SearchCommonVO<SalesOutBillVO> condition) {
        PageHelperPlus.orderBy("create_date desc");
        PageHelperPlus.startPage(condition.getPageNum(), condition.getPageSize());
        List<SalesOutBillDO> billDOList = salesOutBillMapper.availableReturnList(condition.getFilters());
        List<SalesOutBillVO> voList = new ArrayList<>();
        for (SalesOutBillDO salesOutBillDO : billDOList) {
            SalesOutBillVO model = new SalesOutBillVO();
            BeanUtils.copyProperties(salesOutBillDO, model);
            voList.add(model);
        }
        PageCommonVO<SalesOutBillVO> result = new PageCommonVO<>();
        result.setPageInfo(new PageInfo<>(billDOList));
        result.setPageInfoList(voList);
        return result;
    }

    private ErrorCode checkBillFinished(String billNo, String billId, String orgId) throws Exception {
        List<SalesOutBillDetailDO> detailDOList = salesOutBillDetailMapper.selectBySalesOutBillNo(billId);
        if (ListUtil.isNullOrEmpty(detailDOList)) {
            throw new Exception("未查询到销售出库单详情列表");
        }
        boolean manul = false;
        boolean flag = true;
        int status;
        for (SalesOutBillDetailDO temp : detailDOList) {
            if (3 == temp.getOutboundStatus()) {
                manul = true;
            }
            if (3 == temp.getOutboundStatus() || 2 == temp.getOutboundStatus()) {
                //完成状态
                continue;
            }
            flag = false;
        }
        if (flag) {
            if (manul) {
                status = 3;
            } else {
                status = 2;
            }
        } else {
            status = 1;
        }
        salesOutBillMapper.updateStatus(billNo, status, orgId, new Date());
        warehouseDeliveryService.updateState(billNo, status, orgId);
        return ErrorCode.Success;
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean updateByOutbound(String salesOutBillNo, String materialsNo, BigDecimal realAmount,
                                    Integer singelState, Integer totalState, String orgId, boolean updateReceipt) throws Exception {
        SalesOutBillDO salesOutBillDO = salesOutBillMapper.selectBySalesOutBillNo(salesOutBillNo);
        if (salesOutBillDO == null) {
            return false;
        }

        SalesOutBillDetailDO billDetailDO = salesOutBillDetailMapper.selectBySalesBillNoMal(salesOutBillNo, materialsNo, orgId);
        if (null == billDetailDO) {
            return false;
        }

        BigDecimal outboundQty = billDetailDO.getOutboundQty() == null ? BigDecimal.ZERO : billDetailDO.getOutboundQty();
        BigDecimal issuedQty = billDetailDO.getIssuedQty() == null ? BigDecimal.ZERO : billDetailDO.getIssuedQty();
        BigDecimal thisOutboundQty = realAmount.subtract(outboundQty);
        billDetailDO.setOutboundQty(realAmount);
        billDetailDO.setIssuedQty(issuedQty.add(thisOutboundQty));
        billDetailDO.setOutboundStatus(singelState.shortValue());
        boolean success = salesOutBillDetailMapper.updateByPrimaryKeySelective(billDetailDO) > 0;
        if (success) {
            Date outboundDate = new Date();
            success = salesOutBillMapper.updateStatus(salesOutBillNo, totalState, orgId, outboundDate) > 0;
            if (!success) {
                return false;
            }
            //  如果订单类型是赠送更新车辆额度
           /* Short billType = salesOutBillDO.getBillType();
            if (3 == billType) {
                String salesBillNo = salesOutBillDO.getSalesBillNo();
                SalesBillDO salesBillDO = salesBillMapper.selectBySalesBillNo(salesBillNo);
                if (null == salesBillDO) {
                    return false;
                }
                BigDecimal singlePrice = billDetailDO.getSinglePrice();
                BigDecimal outQuota = realAmount.multiply(singlePrice).setScale(4, BigDecimal.ROUND_DOWN);
                ErrorCode errorCode = dealerVehicleService.updateQuota(salesBillDO, outQuota, orgId);
                if (ErrorCode.Success != errorCode) {
                    return false;
                }
            }*/

            //更新出库数量
            boolean updateResult = salesBillService.updateCreateOutStatus(salesOutBillDO.getSalesBillNo(), materialsNo,
                    null, thisOutboundQty, null, outboundDate);
            if (!updateResult) {
                return false;
            }
        }
        return success;
    }

    public void export(List<String> ids) throws Exception {
        List<SalesOutBillDO> voList = new ArrayList<>();
        for (String id : ids) {
            SalesOutBillDO salesOutBillDO = salesOutBillMapper.selectByPrimaryKey(id);
            voList.add(salesOutBillDO);
        }
        invokeExport(voList);
    }

    public void exportAll(SalesOutBillVO condition) throws Exception {
        //PageHelperPlus.startPage(0, 0, "id desc");
        List<SalesOutBillDO> doList = salesOutBillMapper.list(condition);
        invokeExport(doList);
    }

    private void invokeExport(List<SalesOutBillDO> voList) throws Exception {
        String title = "销售出库数据导出";
        String[] rowsName = new String[]{"序号", "出库单号", "销售单号", "借用单号", "客户名称", "制单人", "制单时间",
                "单据类型", "服务人员", "出库状态", "出库时间", "发出仓库",
                "总价", "结算状态", "备注", "零件号", "零件名称", "单位", "订单总数", "已发数量", "本次发货", "单价"};
        List<Object[]> dataList = new ArrayList<>();
        Object[] objs;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for (int i = 0; i < voList.size(); i++) {
            SalesOutBillDO salesOutBillDO = voList.get(i);
            List<SalesOutBillDetailDO> detailDOList = salesOutBillDetailMapper.selectBySalesOutBillNo(salesOutBillDO.getSalesOutBillNo());
            for (SalesOutBillDetailDO detailDO : detailDOList) {
                objs = new Object[rowsName.length];
                objs[0] = i + 1;
                objs[1] = salesOutBillDO.getSalesOutBillNo();
                objs[2] = salesOutBillDO.getSalesBillNo();
                objs[3] = salesOutBillDO.getBorrowBillNo();
                objs[4] = salesOutBillDO.getClientName();
                objs[5] = salesOutBillDO.getGeneratePerson();
                objs[6] = sdf.format(salesOutBillDO.getGenerateDate());
                objs[7] = getBillType(salesOutBillDO.getBillType());
                objs[8] = salesOutBillDO.getServicePersonName();
                objs[9] = getOutboundStatus(salesOutBillDO.getOutboundStatus());
                if (null != salesOutBillDO.getOutboundDate()) {
                    objs[10] = sdf.format(salesOutBillDO.getOutboundDate());
                } else {
                    objs[10] = "";
                }
                objs[11] = salesOutBillDO.getOutArea();
                objs[12] = salesOutBillDO.getTotalPrice();
                objs[13] = getCheckState(salesOutBillDO.getCheckState());
                objs[14] = salesOutBillDO.getRemark();
                objs[15] = detailDO.getMaterialNo();
                objs[16] = detailDO.getMaterialDes();
                objs[17] = detailDO.getUnit();
                objs[18] = detailDO.getTotalOrderQty();
                objs[19] = detailDO.getIssuedQty();
                objs[20] = detailDO.getThisShipQty();
                objs[21] = detailDO.getSinglePrice();
                dataList.add(objs);
            }
        }
        ExportUtil exportUtil = new ExportUtil(title, rowsName, dataList);
        exportUtil.export(response);
    }

    private String getOutboundStatus(Short outboundStatus) {
        switch (outboundStatus) {
            case 0:
            default:
                return "未出库";
            case 1:
                return "部分出库";
            case 2:
                return "出库";
            case 3:
                return "强制结单";
        }
    }

    private String getIsPrint(Short isPrint) {
        switch (isPrint) {
            case 0:
            default:
                return "未打印";
            case 1:
                return "打印";
        }
    }

    private String getCheckState(Short isPrint) {
        switch (isPrint) {
            case 0:
            default:
                return "未结算";
            case 1:
                return "部分结算";
            case 2:
                return "已结算";
        }
    }

    private String getBillType(Short billType) {
        switch (billType) {
            case 1:
            default:
                return "普通";
            case 2:
                return "三包";
            case 3:
                return "赠送";
        }
    }

    public SaleOutAddVO getRefundInfo(String id) {
        SaleOutAddVO result = new SaleOutAddVO();
        SalesOutBillDO salesOutBillDO = salesOutBillMapper.selectByPrimaryKey(id);
        if (salesOutBillDO == null) {
            return result;
        }

        SalesOutBillVO salesOutBillVO = new SalesOutBillVO();
        BeanUtils.copyProperties(salesOutBillDO, salesOutBillVO);

        result.setHeaderInfo(salesOutBillVO);
        List<SalesOutBillDetailVO> listVO = new ArrayList<>();
        List<SalesOutBillDetailDO> detailDOList = salesOutBillDetailMapper.getRefundInfo(salesOutBillDO.getSalesOutBillNo());
        detailDOList.forEach(x -> {
            SalesOutBillDetailVO salesBillDetailVO = new SalesOutBillDetailVO();
            BeanUtils.copyProperties(x, salesBillDetailVO);
            BigDecimal actualReturnQty = salesBillDetailVO.getActualReturnQty();
            BigDecimal remainReturnQty = salesBillDetailVO.getOutboundQty().subtract(actualReturnQty);
            salesBillDetailVO.setRemainReturnQty(remainReturnQty);
            listVO.add(salesBillDetailVO);
        });
        result.setMaterialList(listVO);
        return result;
    }

//    @Transactional(rollbackFor = Exception.class)
//    public ErrorCode postSap(String id, String orgId, String  userId, String username)
//        throws Exception {
//
//        SalesOutBillDO salesOutBillDO = salesOutBillMapper.selectByPrimaryKey(id);
//        if (null == salesOutBillDO) {
//            return ErrorCode.ImportExcelNoData;
//        }
//
//        if (!salesOutBillDO.canPost()) {
//            return ErrorCode.SalesOutBillPostStatusError;
//        }
//
//        CompanyInfoVO companyInfoVO = companyInfoService.info(orgId);
//        if (companyInfoVO == null || companyInfoVO.getSapCode() == null) {
//            LogHelper.error("同步sap过账时企业不存在", ErrorCode.RequestIdError.getCode());
//            return ErrorCode.ImportExcelNoData;
//        }
//      // 该接口仅提供给施维英使用
//      if (!CompanyUtil.isSWY(companyInfoVO.getSapCode())) {
//        throw new Exception("当前企业不可过账");
//      }
//
//      ImportParam importParam = fillImportParam(salesOutBillDO, companyInfoVO, userId, username);
//        LogHelper.monitor("========调用销售出库单过账接口开始========");
//        OutputParam outputParam = SAPCommonUtil.getData(importParam);
//        LogHelper.monitor("========调用销售出库单过账接口结束========");
//        if (null == outputParam || outputParam.getCode() != 0) {
//            LogHelper.error("sap返回值为null", ErrorCode.RequestIdError.getCode());
//            throw new Exception("SAP无返回值");
//        }
//        SalesOutPostDO salesOutPostDO = assemblyPostInfo(salesOutBillDO, outputParam);
//
//        // 数据无变化的情况下重复点击“过账”，以下字段均为null
////        if (null == sapDeliveryNoteDO.getSapSaleOrder() && null == sapDeliveryNoteDO.getSapOutBill()
////                && null == sapDeliveryNoteDO.getMaterialsNo() && null == sapDeliveryNoteDO.getIsPosting()) {
////            throw new Exception("操作无效，请勿重复操作");
////        }
//        if (null == salesOutPostDO.getSapSaleOrder() && null == salesOutPostDO.getSapOutBill()
//            && null == salesOutPostDO.getMaterialsNo() && null == salesOutPostDO.getPostFlag()) {
//            return ErrorCode.Success;
//        }
//        saveOrUpdatePostInfo(salesOutPostDO, userId, username);
//        return ErrorCode.Success;
//    }

    private void saveOrUpdatePostInfo(SalesOutPostDO salesOutPostDO, String userId, String username) {
        salesOutPostDO.setPostId(userId);
        salesOutPostDO.setPostName(username);
        salesOutPostDO.setPostTime(new Date());
        if (org.apache.commons.lang3.StringUtils.isBlank(salesOutPostDO.getId())) {
            salesOutPostDO.setId(fastGenClient.textGuid().getValue());
            salesOutPostMapper.insert(salesOutPostDO);
            return;
        }
        salesOutPostMapper.update(salesOutPostDO);
    }

//    /**
//     * 填充过账相关参数
//     *
//     * @param salesOutBillDO
//     * @param companyInfoVO
//     * @return
//     */
//    private ImportParam fillImportParam(SalesOutBillDO salesOutBillDO, CompanyInfoVO companyInfoVO, String userId, String userName)
//        throws Exception {
//        List<SalesOutBillDetailDO> detailDOList = salesOutBillDetailMapper.selectBySalesOutBillNo(salesOutBillDO.getSalesOutBillNo());
//
//        SalesOutPostDO salesOutPostDO = salesOutPostMapper.getByOutId(salesOutBillDO.getId());
//        if (null != salesOutPostDO && salesOutPostDO.hasPosted()) {
//            throw new Exception("单据已过账");
//        }
//        if (null == salesOutPostDO) {
//            salesOutPostDO = new SalesOutPostDO();
//        }
//        ImportParam importParam = new ImportParam();
//        importParam.setFunction("ZPMSBJ_SET_VA01N");
//        Map<String, String> map = new HashMap<>();
//        // 销售组织
//        map.put("VKORG", companyInfoVO.getSapCode());
//        // 售达方
////        map.put("KUNNR_AG", deliveryNoteDO.getSold());
//        // 送达方
////        map.put("KUNNR_WE", deliveryNoteDO.getDelivery());
//        // 发出库位
////        map.put("LGORT_O", deliveryNoteDO.getSapOutArea());
//        map.put("LGORT_O", salesOutBillDO.getOutArea());
//        // 备注
//        map.put("INFO", salesOutBillDO.getRemark());
//        // 制单人
//        map.put("KUNNR_Z6", deliveryNoteMapper.findUserSapCode(salesOutBillDO.getCreateId()));
//        // 提前过账，可能sap系统已经返回过“VBELN”，“DELIV_NUMB”的值
//        if (StringUtil.isNullOrEmpty(salesOutPostDO.getSapOutBill())) {
//            map.put("DELIV_IN_PR", salesOutPostDO.getSapOutNo());
//        } else {
//            // 外向交货单号
//            map.put("DELIV_IN", salesOutPostDO.getSapOutBill());
//        }
//        if (!StringUtil.isNullOrEmpty(salesOutPostDO.getSapSaleOrder())) {
//            // 销售订单号
//            map.put("VBELN_IN", salesOutPostDO.getSapSaleOrder());
//        }
//        // 单据类型固定为ZS，SAP那边与发货通知单过账区分
//        map.put("AUART", "ZS");
//        importParam.setCommonParamMap(map);
//        Map<String, List<Map<String, String>>> tableParamMap = new HashMap<>();
//        List<Map<String, String>> list = new ArrayList<>();
//        for (SalesOutBillDetailDO detailDO : detailDOList) {
//            Map<String, String> mapd = new HashMap<>();
//            // 零件编码
//            mapd.put("MATNR", detailDO.getMaterialNo());
//
//            if (detailDO.getOutboundStatus() == 0) {
//                continue;
//            }
//            // 数量
//            mapd.put("ZMENG", detailDO.getOutboundQty().toString());
//
//            // 基本计量单位
//            mapd.put("MEINS", detailDO.getUnit());
//            // 价格
//            mapd.put("KBETR_ZPR4", takeDecimals(detailDO.getSinglePrice()).toString());
//            // 价格组
//            mapd.put("KONDA", "");
//            list.add(mapd);
//
//            //插入过账记录
//            insertPostRecord(salesOutBillDO.getId(), salesOutBillDO.getSalesOutBillNo(), detailDO.getMaterialNo(), detailDO.getOutboundQty(),
//                userId, userName, salesOutBillDO.getOrgId());
//        }
//        tableParamMap.put("ZWJBJ_VA01_IN", list);
//        importParam.setTableParamMap(tableParamMap);
//        importParam.setSapCode(companyInfoVO.getSapCode());
//        return importParam;
//    }
//
//    /**
//     * 请求sap执行的顺序一定是：创建销售订单->创建外向交货单->外向交货单发货
//     *
//     * @param
//     * @param outputParam
//     * @return
//     * @throws Exception
//     */
//    private SalesOutPostDO assemblyPostInfo(SalesOutBillDO salesOutBillDO, OutputParam outputParam) throws Exception {
//
//        SalesOutPostDO salesOutPostDO = salesOutPostMapper.getByOutId(salesOutBillDO.getId());
//
//        if (null == salesOutPostDO) {
//            salesOutPostDO = new SalesOutPostDO();
//        }
//        salesOutPostDO.setSalesOutId(salesOutBillDO.getId());
//        salesOutPostDO.setDeleteFlag(DELETE_FLAG_NO);
//        //创建销售订单结果
//        if (null == salesOutPostDO.getSapSaleOrder()) {
//            if (!RESULT_OK.equals(outputParam.getDataHeader().get("RETURNCODE1"))) {
//                LogHelper.error("调用过账接口失败，" + outputParam.getDataHeader().get("RETURNMSG1"), ErrorCode.RequestIdError.getCode());
//                addRecord(salesOutBillDO, salesOutPostDO, outputParam.getDataHeader().get("RETURNMSG1"), salesOutBillDO.getOrgId());
//                throw new Exception(outputParam.getDataHeader().get("RETURNMSG1"));
//            } else {
//                salesOutPostDO.setSapSaleOrder(outputParam.getDataHeader().get("VBELN"));
//            }
//        }
//        //创建外向交货单结果
//        if (null == salesOutPostDO.getSapOutBill()) {
//            if (!RESULT_OK.equals(outputParam.getDataHeader().get("RETURNCODE2"))) {
//                LogHelper.monitor("调用过账接口失败，原因可能是操作提前过账，" + outputParam.getDataHeader().get("RETURNMSG2"));
//                addRecord(salesOutBillDO, salesOutPostDO, outputParam.getDataHeader().get("RETURNMSG2"), salesOutBillDO.getOrgId());
//            } else {
//                salesOutPostDO.setSapOutBill(outputParam.getDataHeader().get("DELIV_NUMB"));
//            }
//        }
//        //外向交货单发货结果
//        if (!RESULT_OK.equals(outputParam.getDataHeader().get("RETURNCODE3"))) {
//            LogHelper.monitor("调用过账接口失败，原因可能是操作提前过账，" + outputParam.getDataHeader().get("RETURNMSG3"));
//            addRecord(salesOutBillDO, salesOutPostDO, outputParam.getDataHeader().get("RETURNMSG3"), salesOutBillDO.getOrgId());
//        } else {
//            salesOutPostDO.setMaterialsNo(outputParam.getDataHeader().get("MBLNR"));
//            salesOutPostDO.setPostFlag(POST_FLAG_YES);
//
//            //过账成功，删除过账失败记录
//            sappostErrorRecordService.updateDel(salesOutBillDO.getSalesOutBillNo(), salesOutBillDO.getOrgId());
//        }
//        return salesOutPostDO;
//    }

    /**
     * 自动新增销售出库单
     *
     * @return
     */
//    @Transactional(rollbackFor = Exception.class)
//    public synchronized ErrorCode autoSubmit(SaleOutAutoAddVO addVO, String userId, String orgId, String userName) throws Exception {
//
//        List<SaleOutAutoAddDetailVO> materialList = addVO.getMaterialList();
//        if (CollectionUtils.isEmpty(materialList)) {
//            throw new Exception("零件列表不能为空");
//        }
//        Short billType = addVO.getBillType();
//
//        //*********1、创建销售出库单主表*********
//        SalesOutBillDO outBillDO = new SalesOutBillDO();
//
//        String id = fastGenClient.newGuidText().getValue();
//        if (StringUtils.isBlank(id)) {
//            throw new Exception("新增销售出库单主键失败");
//        }
//        outBillDO.setId(id);
//        String salesOutBillNo = genDocumentService.getDocumentNo(BillDesc.SalesOutNo);
//        outBillDO.setSalesBillNo("0");
//        outBillDO.setClientName("0");//不为空，默认赋值0
//        outBillDO.setSalesOutBillNo(salesOutBillNo);
//        outBillDO.setBillType(billType);
//        outBillDO.setCheckState((short) 0);
//        if (SaleOutEnum.SaleBillTypeThreePack.getCode() == billType) {//三包
//            outBillDO.setCheckState((short) 2);
//        }
//        outBillDO.setCreateSaleStatus((short) 0);//未创建
//        outBillDO.setGenerateDate(new Date());
//        outBillDO.setGeneratePerson(userName);
//        outBillDO.setIsState((short) 1);//提交状态
//        outBillDO.setOrgId(orgId);
//        outBillDO.setOutArea(materialList.get(0).getWarehouseCode());//默认取第一个零件仓库
//        outBillDO.setOutboundStatus((short) 2);
//        outBillDO.setOutboundDate(new Date());
//        outBillDO.setCreateDate(new Date());
//        outBillDO.setCreateId(userId);
//        outBillDO.setUpdateDate(new Date());
//        outBillDO.setUpdateId(userId);
//
//        //生成发票号
//        String invoiceNo = genInvoiceNo(orgId);
//        outBillDO.setInvoiceNo(invoiceNo);
//
//        BigDecimal totalCostPrice = BigDecimal.ZERO;
//        BigDecimal totalPrice = BigDecimal.ZERO;
//
//        //*********2、创建销售出库单详情表*********
//        List<DeliveryNoteDetailVO> deliveryNoteDetailVOList = new ArrayList<>();
//        SalesOutBillDetailDO detailDO;
//        for (SaleOutAutoAddDetailVO detailVO : materialList) {
//            if (detailVO.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
//                throw new Exception("零件【" + detailVO.getMaterialNo() + "】数量必须大于0");
//            }
//            if (detailVO.getSplitAmount().compareTo(BigDecimal.ZERO) <= 0) {
//                throw new Exception("零件【" + detailVO.getMaterialNo() + "】拆出数量必须大于0");
//            }
//            detailDO = new SalesOutBillDetailDO();
//            BeanUtils.copyProperties(detailVO, detailDO);
//            String detailId = fastGenClient.newGuidText().getValue();
//            if (StringUtils.isBlank(detailId)) {
//                throw new Exception("新增销售出库单详情主键失败");
//            }
//            detailDO.setId(detailId);
//            detailDO.setSalesBillOutNo(salesOutBillNo);
//            detailDO.setSalesBillNo("0");
//            detailDO.setOutboundQty(detailVO.getSplitAmount());//本次发货
//            detailDO.setIssuedQty(detailVO.getSplitAmount());
//            detailDO.setThisShipQty(detailVO.getSplitAmount());
//            detailDO.setTotalOrderQty(detailVO.getSplitAmount());//总数
//            //预处理
//            preJckSalesOutBillDetailDO(userId, orgId, detailDO);
//
//            totalCostPrice = totalCostPrice.add(detailDO.getCostSubtotal());
//            totalPrice = totalPrice.add(detailDO.getSinglePrice().multiply(detailDO.getThisShipQty()));
//
//            int insCount = salesOutBillDetailMapper.insertSelective(detailDO);
//            if (insCount <= 0) {
//                throw new Exception("新增销售出库单详情失败");
//            }
//        }
//
//        //创建销售出库单
//        outBillDO.setTotalPrice(totalPrice);
//        outBillDO.setCostTotal(totalCostPrice);
//        int insSalesOutCount = salesOutBillMapper.insertSelective(outBillDO);
//        if (insSalesOutCount <= 0) {
//            throw new Exception("新增销售出库单失败");
//        }
//
//        //*********3、创建出库事务表*********
//        // 新增出库单时新增发货事物单
//        DeliveryNoteAddVO deliveryNoteAddVO = new DeliveryNoteAddVO();
//        DeliveryNoteVO deliveryNoteVO = new DeliveryNoteVO();
//        deliveryNoteVO.setDeliveryNo(salesOutBillNo);
//        deliveryNoteVO.setOutLocation(outBillDO.getOutArea());
//        deliveryNoteAddVO.setHeaderInfo(deliveryNoteVO);
//
//        //合并零件数量
//        Map<String, List<SaleOutAutoAddDetailVO>> detailMap = materialList.stream().collect(Collectors.groupingBy(SaleOutAutoAddDetailVO::getMaterialNo));
//        DeliveryNoteDetailVO deliveryNoteDetailVO;
//        for (Map.Entry<String, List<SaleOutAutoAddDetailVO>> entry : detailMap.entrySet()) {
//            deliveryNoteDetailVO = new DeliveryNoteDetailVO();
//            deliveryNoteDetailVO.setMaterialsNo(entry.getKey());
//            List<SaleOutAutoAddDetailVO> materList = entry.getValue();
//            BigDecimal deliveryQty = materList.stream().map(SaleOutAutoAddDetailVO::getSplitAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
//            deliveryNoteDetailVO.setMaterialsDes(materList.get(0).getMaterialDes());
//            deliveryNoteDetailVO.setUnit(materList.get(0).getUnit());//单位
//            deliveryNoteDetailVO.setDeliveryQty(deliveryQty);
//            deliveryNoteDetailVOList.add(deliveryNoteDetailVO);
//        }
//        deliveryNoteAddVO.setMaterialList(deliveryNoteDetailVOList);
//
//        boolean deliveryFlag = warehouseDeliveryService.saveByDeliveryNoteOut(deliveryNoteAddVO, userId, orgId);
//        if (!deliveryFlag) {
//            throw new Exception("新增发货事务单失败");
//        }
//
//        //*********4、自动销售出库*********
//        WarehouseDeliveryRecordAddVO warehouseDeliveryRecordVO;
//        for (SaleOutAutoAddDetailVO detailVO : materialList) {
////            List<WarehouseInventoryVO> inventoryVOList = new ArrayList<>();
////            warehouseInventoryService.findByBarCodeFromInventory(salesOutBillNo, detailVO.getBarcode(), orgId, inventoryVOList, null);
//
//            warehouseDeliveryRecordVO = new WarehouseDeliveryRecordAddVO();
//            warehouseDeliveryRecordVO.setBusinessOrder(salesOutBillNo);//销售出库单
//            warehouseDeliveryRecordVO.setSplitAmount(detailVO.getSplitAmount());//拆分数量
//
//            if (detailVO.getAmount().compareTo(detailVO.getSplitAmount()) != 0) {
//                //自动拆分条码
//                SplitNumVO splitNumVO = new SplitNumVO(detailVO.getBarcode(), detailVO.getSplitAmount(), salesOutBillNo);
//                BarcodeManageVO barcodeManageVO = barcodeService.splitNum(splitNumVO, userId, orgId);
//                if (ObjectUtils.isEmpty(barcodeManageVO)) {
//                    throw new Exception("拆分条码【" + detailVO.getBarcode() + "】失败");
//                }
//                warehouseDeliveryRecordVO.setBarCode(barcodeManageVO.getBarcode());
//                warehouseDeliveryRecordVO.setAmount(barcodeManageVO.getCurrentQty());//出库数量
//            } else {
//                warehouseDeliveryRecordVO.setBarCode(detailVO.getBarcode());
//                warehouseDeliveryRecordVO.setAmount(detailVO.getAmount());//出库数量
//            }
//
//            ErrorCode errorCode = warehouseDeliveryRecordService.jckAdd(warehouseDeliveryRecordVO, userId, orgId, true);
//            if (errorCode.getCode() != ErrorCode.Success.getCode()) {
//                throw new Exception("销售出库单自动出库失败--" + errorCode.getDesc());
//            }
//        }
//        return ErrorCode.Success;
//    }

    private void preJckSalesOutBillDetailDO(String userId, String orgId, SalesOutBillDetailDO detailDO) {
        detailDO.setIsState((short) 1);
        detailDO.setCreateDate(new Date());
        detailDO.setCreateId(userId);
        detailDO.setOrgId(orgId);
        detailDO.setOutboundStatus((short) 2);
        detailDO.setUpdateDate(new Date());
        detailDO.setUpdateId(userId);

        //查询赋值
        //意向占用
        EnableAndOccupyVO enableAndOccupyVO = warehouseInventoryService.findEnableAndOccupyNum(detailDO.getMaterialNo(), orgId, null);
        if (enableAndOccupyVO != null) {
            detailDO.setRealStockQty(enableAndOccupyVO.getEnableNum());
            detailDO.setIntentOccupation(enableAndOccupyVO.getIntentionNum());
            detailDO.setShipOccupation(enableAndOccupyVO.getDeliveryNum());
        }

        //价格
        PriMaterialsDO priMaterialsDO = priMaterialsMapper.itemByNo(detailDO.getMaterialNo(), orgId);
        if (null != priMaterialsDO) {
            detailDO.setSafetyStock(priMaterialsDO.getSafeAmount());
            detailDO.setOnlineStock(priMaterialsDO.getMaxAmount());
            detailDO.setSinglePrice(priMaterialsDO.getPrice() == null ? BigDecimal.ZERO :
                    DecimalUtil.roundDecimal4Output(priMaterialsDO.getPrice()));
            detailDO.setCostPrice(priMaterialsDO.getStandardPrice() == null ? BigDecimal.ZERO :
                    DecimalUtil.roundDecimal4Output(priMaterialsDO.getStandardPrice()));
            detailDO.setCostSubtotal(detailDO.getCostPrice().multiply(detailDO.getThisShipQty()));//成本小计
        } else {
            detailDO.setSinglePrice(BigDecimal.ZERO);//单价
            detailDO.setCostPrice(BigDecimal.ZERO);
            detailDO.setCostSubtotal(BigDecimal.ZERO);
        }

        MaterialLocationRelationVO materialLocationRelationVO = new MaterialLocationRelationVO();
        materialLocationRelationVO.setMaterialNo(detailDO.getMaterialNo());
        materialLocationRelationVO.setOrgId(orgId);
        List<MaterialLocationRelationVO> voList = materialLocationRelationMapper.list(materialLocationRelationVO);
        if (CollectionUtils.isNotEmpty(voList)) {//默认储位
            detailDO.setDefaultStorage(voList.get(0).getLocationCode());
        }
    }

    public List<SalesOutBillDetailVO> listDetailByStatus(String orgId) {
        List<SalesOutBillDetailDO> billDetailDOList = salesOutBillDetailMapper.listDetailByStatus(orgId);
        List<SalesOutBillDetailVO> billDetailVOList = BeanUtil.do2bo4List(billDetailDOList, SalesOutBillDetailVO.class);
        if (CollectionUtils.isNotEmpty(billDetailVOList)) {
            List<String> materialsNoList = billDetailVOList.stream().map(SalesOutBillDetailVO::getMaterialNo).distinct().collect(Collectors.toList());
            MaterialsSearchVO model = new MaterialsSearchVO();
            model.setOrgId(orgId);
            model.setMaterialsList(materialsNoList);
            List<MaterialsVO> materialsVOS = priMaterialsMapper.listByMaterialsNos(model);
            Map<String, MaterialsVO> materialsVOMap = new HashMap<>();
            if (CollectionUtils.isNotEmpty(materialsVOS)) {
                materialsVOMap = materialsVOS.stream().collect(Collectors.toMap(MaterialsVO::getMaterialsNo, Function.identity(), (k1, k2) -> k2));
            }
            for (SalesOutBillDetailVO detailVO : billDetailVOList) {
                if (materialsVOMap.containsKey(detailVO.getMaterialNo())) {
                    MaterialsVO materialsVO = materialsVOMap.get(detailVO.getMaterialNo());
                    detailVO.setSinglePrice(materialsVO.getPrice() == null ? BigDecimal.ZERO : DecimalUtil.divideHundred(materialsVO.getPrice()));
                    detailVO.setCostPrice(materialsVO.getStandardPrice() == null ? BigDecimal.ZERO : DecimalUtil.divideHundred(materialsVO.getStandardPrice()));
                    detailVO.setCostSubtotal(detailVO.getCostPrice().multiply(detailVO.getThisShipQty()));
                }
            }

        }
        return billDetailVOList;
    }
//
//
//    private static BigDecimal takeDecimals(BigDecimal integer) {
//        if (integer == null) {
//            return new BigDecimal(0);
//        }
//        return integer.divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
//    }
//
////    private void insertPostRecord(String billId, String billNo, String materialsNo, BigDecimal outAmount, String userId, String userName, String orgId) {
////        BigDecimal postQty = sapPostRecordMapper.getAllPostedQty(billId, billNo, materialsNo, null);
////        SapPostRecord record = new SapPostRecord();
////        record.setPostQty(outAmount.subtract(postQty));
////        record.setCreateTime(new Date());
////        record.setCreateName(userName);
////        record.setCreateId(userId);
////        record.setOrgId(orgId);
////        record.setMaterialsNo(materialsNo);
////        record.setId(fastfastGenClient.textGuid().getValue());
////        record.setBillType(billNo.substring(0, 4));
////        record.setBillNo(billNo);
////        record.setBillId(billId);
////        sapPostRecordMapper.insert(record);
////    }
//
////    private void addRecord(SalesOutBillDO salesOutBillDO, SalesOutPostDO salesOutPostDO, String errorMessage, String orgId) {
////        SappostErrorRecordDO sappostErrorRecordDO = new SappostErrorRecordDO();
////        sappostErrorRecordDO.setErrorMessage(errorMessage);
////        sappostErrorRecordDO.setBusinessNo(salesOutBillDO.getSalesOutBillNo());
////        sappostErrorRecordDO.setOrgId(orgId);
////        sappostErrorRecordDO.setOrderCreateId(salesOutBillDO.getCreateId());
////        sappostErrorRecordDO.setOrderCreateName(commonService.getUserName(salesOutBillDO.getCreateId()));
////        sappostErrorRecordDO.setSapOrderNo(salesOutPostDO.getSapSaleOrder());
////        sappostErrorRecordService.add(sappostErrorRecordDO);
////    }
//
//    /**
//     * 生成单号。此处不用orgId也没问题，防止以后功能扩展别的公司也用，加入区分一下
//     * 定时任务（DocumentNoGenFreshTask）每天0时清除redis值，第二天继续从0自增
//     *
//     * @param orgId
//     * @return
//     */
//    private String genInvoiceNo(String orgId) throws Exception {
//        //查询客户公司简称
//        CompanyInfoDO companyInfoDO = companyInfoMapper.item(orgId);
//        if (null == companyInfoDO) {
//            throw new Exception("公司不存在");
//        }
//        if (StringUtils.isEmpty(companyInfoDO.getShortName())) {
//            throw new Exception("公司简称不存在，请联系管理员");
//        }
//        StringBuilder invoiceNo = new StringBuilder(companyInfoDO.getShortName());
//        invoiceNo.append(DateFormatUtils.format(new Date(), "yyyyMMdd"));
//        String invoiceSuffixRedisKey = JCK_INVOICE_NO_GEN_PRE + ":" + orgId;
//        //从redis中取出发票号后缀
//        Long invoiceSuffix = JedisUtils.incrByKey4Jck(invoiceSuffixRedisKey);
//        return invoiceNo.append(String.format("%03d", invoiceSuffix)).toString();
//    }
}
